#include "Lista.h"


struct listaNode{
   void* item;
   struct listaNode* proximo;
   struct listaNode* anterior;
};


Lista::Lista(){

	this->primeiro=(struct listaNode*)malloc(sizeof( struct listaNode));
	this->ultimo=(struct listaNode*)malloc(sizeof( struct listaNode));

	this->resetLista();
}


void Lista::resetLista(){

	this->primeiro->item=NULL;
	this->ultimo->item=NULL;

	this->iterador=ultimo;
	this->numeroElementos=0;

	this->primeiro->proximo=ultimo;
	this->primeiro->anterior=NULL;

	this->ultimo->anterior=primeiro;
	this->ultimo->proximo=NULL;
}

Lista::~Lista(){
	struct listaNode* no;
	struct listaNode* aux;

	/*destroise todos os nos*/
	for(no=this->primeiro;no!=NULL;no=aux){
		aux=no->proximo;
		free(no);
		no=NULL;
	}
}

void Lista::deleteItems(void apagaItem(void*)){
	struct listaNode* no;
	struct listaNode* proximoNo;

	no=this->primeiro->proximo;
	for(;no->proximo!=NULL;no=proximoNo){
		apagaItem(no->item);
		proximoNo=no->proximo;
		free(no);
		no=NULL;
	}
	this->resetLista();
}

void* Lista::showElementNumber(int x){
	struct listaNode* no;

	for(no=(this->primeiro)->proximo;no->proximo!=NULL;no=no->proximo){
		if(x==0)
			return no->item;
		else
			x--;
	}
	return NULL;
}

void* Lista::retiraItemPorChave(void* chave ,int escolha(void* item,void* chave)){
	struct listaNode* actual;
	struct listaNode* ultimo;
	void* resposta;

	ultimo=this->ultimo;
	actual=(this->primeiro)->proximo;

	while(actual!=ultimo){
		if(escolha(actual->item,chave)){

			resposta=actual->item;
			(actual->anterior)->proximo=actual->proximo;
			(actual->proximo)->anterior=actual->anterior;
			free(actual);
			actual=NULL;

			this->numeroElementos--;
			return resposta;
		}

		actual=actual->proximo;
	}
	return NULL;
}


int Lista::numeroItems(){
	return this->numeroElementos;
}

void* Lista::encontraItem(void* chave ,int escolha(void* item,void* chave)){
	struct listaNode* actual;
	struct listaNode* ultimo;

	ultimo=this->ultimo;
	actual=(this->primeiro)->proximo;

	while(actual!=ultimo){
		if(escolha(actual->item,chave))
			return actual->item;

		actual=actual->proximo;
	}
	return NULL;
}


void Lista::insere(void* item){
	struct listaNode* no;

	no=(struct listaNode*)malloc(sizeof(struct listaNode));
	no->item=item;

	no->proximo=(this->primeiro)->proximo;
	no->anterior=this->primeiro;

	(no->proximo)->anterior=no;
	(this->primeiro)->proximo=no;

	this->numeroElementos++;
}

void Lista::insereUlt(void* item){
	struct listaNode* no;

	no=(struct listaNode*)malloc(sizeof(struct listaNode));
	no->item=item;

	no->proximo=this->ultimo;
	no->anterior=(this->ultimo)->anterior;

	(no->anterior)->proximo=no;
	(this->ultimo)->anterior=no;

	this->numeroElementos++;
}

void* Lista::first(){
	struct listaNode* no;
	void* item;

	if ((this->primeiro)->proximo->proximo==NULL)
		return NULL;

	no=(this->primeiro)->proximo;
	item=no->item;

	(this->primeiro)->proximo=no->proximo;
	(no->proximo)->anterior=this->primeiro;
	free(no);
	no=NULL;

	this->numeroElementos--;
	return item;
}

void* Lista::showFirst(){
	return ((this->primeiro)->proximo)->item;
}

void* Lista::last(){
	struct listaNode* no;
	void* item;

	if ((this->primeiro)->proximo==this->ultimo)
		return NULL;

	no=(this->ultimo)->anterior;
	item=no->item;

	(this->ultimo)->anterior=no->anterior;
	(no->anterior)->proximo=this->ultimo;
	free(no);
	no=NULL;
	return item;
}

void* Lista::showLast(){
	return ((this->ultimo)->anterior)->item;
}

void Lista::resetIterador(){
	this->iterador=(this->primeiro)->proximo;
}

void Lista::nextIterador(){
	if ((this->iterador)->proximo != NULL){
		this->iterador=(this->iterador)->proximo;
	}
}

void* Lista::getItem(){
	return (this->iterador)->item;
}

bool Lista::hasNext(){
	if(((this->iterador)->proximo)!=NULL){
		return (this->iterador)->proximo!=NULL;
	}else{
		return false;
	}
}

void Lista::deleteIterador(){
	struct listaNode* no;

	if (this->iterador == this->ultimo ){
		return;
	}

	no=this->iterador;
	this->iterador=(this->iterador)->proximo;    /* o iterador fica no proximo item*/

	(no->anterior)->proximo=no->proximo;
	(no->proximo)->anterior=no->anterior;
	free(no);
	no=NULL;

	this->numeroElementos--;
}

void Lista::insereOrdem(void* item,int maior(void*,void*)){
	struct listaNode* no;
	struct listaNode* actual;
	struct listaNode* ultimo;

	actual=(this->primeiro)->proximo;
	ultimo=this->ultimo;

	no=(struct listaNode*)malloc(sizeof(struct listaNode));
	no->item=item;

	while(actual!=ultimo && maior(item,actual->item)){
		actual=actual->proximo;
	}

	no->proximo=actual;
	no->anterior=actual->anterior;

	(no->anterior)->proximo=no;
	(no->proximo)->anterior=no;

	this->numeroElementos++;
}

void* Lista::retiraItemPorReferencia(void* item){
	struct listaNode* actual;
	struct listaNode* ultimo;
	void* resposta;
	
	ultimo=this->ultimo;
	actual=(this->primeiro)->proximo;

	while(actual!=ultimo){
		if(item==actual->item){
			resposta=actual->item;
			(actual->anterior)->proximo=actual->proximo;
			(actual->proximo)->anterior=actual->anterior;
			free(actual);
			actual=NULL;

			this->numeroElementos--;
			return resposta;
		}
		actual=actual->proximo;
	}
	return NULL;
}

void* Lista::retiraItem(void* item,int igual(void*,void*)){
	struct listaNode* actual;
	struct listaNode* ultimo;
	void* resposta;
	
	ultimo=this->ultimo;
	actual=(this->primeiro)->proximo;

	while(actual!=ultimo){

		if(igual(item,actual->item)){
			resposta=actual->item;
			(actual->anterior)->proximo=actual->proximo;
			(actual->proximo)->anterior=actual->anterior;
			free(actual);
			actual=NULL;

			this->numeroElementos--;
			return resposta;
		}
		actual=actual->proximo;
	}
	return NULL;
}


void Lista::map(void funcao(void*)){
	struct listaNode* actual=(this->primeiro)->proximo;
	while(actual->proximo!=NULL){
		funcao(actual->item);
		actual=actual->proximo;
	}
}


int Lista::existeItem(void* item,int igual(void*,void*)){
	struct listaNode* actual;
	struct listaNode* ultimo;

	ultimo=this->ultimo;
	actual=(this->primeiro)->proximo;

	while(actual!=ultimo){
		if(igual(item,actual->item))
			return 1;

		actual=actual->proximo;
	}
	return 0;
}

